serverless frameworkをCodePipelineでデプロイするCloudFormationを作成する
目標
CodeCommitにホストされたserverless frameworkのコードをCodePipelineでデプロイするためのCloudFormationを作成します。
serverless frameworkのデプロイコマンドにはstage
オプションがあり、ステージ(環境)ごとにデプロイされるようになっています。それにあわせてCodePipelineもステージ別に作成するように実装してみます。今回はdev
とprd
という2環境むけに作成します。
環境
今回は下記の環境で確認しています。
- serverless framework: 1.67.0
- Codepipeline runtime: Node.js 12.x
serverless framework側 ソースコードの変更
CloudFormationテンプレート作成の前にまずserverless framework側(CodeCommitでホストするソースコード側)で必要な変更を行います。
serverless.yml
serverless.yml
の内容です。service
とregion
は後述するCloudFormationと同じものにします。
service: serverless-deploy-example provider: name: aws runtime: nodejs12.x region: ap-northeast-1 stage: ${opt:stage, self:custom.defaultStage} custom: defaultStage: dev functions: hello: handler: handler.hello
package.json
ここには、デプロイ時に実行するnpm script
コマンドを記述します。ここに環境別向けのデプロイコマンドを記述します。
{ "name": "serverless-deploy-example", "version": "1.0.0", "dependencies": { "serverless": "^1.67.0" }, "devDependencies": {}, "scripts": { "deploy:dev": "sls deploy --stage dev", "deploy:prd": "sls deploy --stage prd" } }
buildspec.yml
CodeBuildで使用するbuildspec.yml
を作成します。${DEPLOY_ENV}
には後述するCloudFormationテンプレートでCodeBuildの環境変数を埋め込むようにします。
version: 0.2 phases: install: runtime-versions: nodejs: 12 commands: - npm install build: commands: - npm run deploy:${DEPLOY_ENV}
CloudFormationテンプレート
次にCloudFormationテンプレートを作成します。
基本となるCloudFormationテンプレートは先日書いたフロントエンド環境をS3にデプロイするCodePipelineをCloudFormationで作成するのものと同じです。
Parameters.Env
でスタック作成時にdev
かprd
を選択するようにします。
AWSTemplateFormatVersion: 2010-09-09 Description: serverless framework deploy pipeline example Parameters: ServiceName: Description: serverless framework deploy pipeline example Type: String Default: serverless-deploy-example Env: Type: String Default: dev AllowedValues: - dev - prd Resources: # ビルド成果物を格納するS3バケット ArtifactsBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub ${ServiceName}-artifacts-${Env} LifecycleConfiguration: Rules: - Id: DeleteRule Status: Enabled ExpirationInDays: 7 # CodeBuild CodeBuildProject: Type: AWS::CodeBuild::Project Properties: Name: !Sub ${ServiceName}-${Env} Artifacts: Type: CODEPIPELINE Source: Type: CODEPIPELINE Environment: ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/standard:3.0 PrivilegedMode: true Type: LINUX_CONTAINER EnvironmentVariables: - Name: DEPLOY_ENV Value: !Sub ${Env} ServiceRole: !GetAtt CodeBuildServiceRole.Arn # CodeBuildのIAMロール CodeBuildServiceRole: Type: AWS::IAM::Role Properties: RoleName: !Sub ${ServiceName}-CodeBuildServiceRole-${Env} Policies: - PolicyName: !Sub ${ServiceName}-CodeBuild-ServiceRolePolicy-${Env} PolicyDocument: Version: '2012-10-17' Statement: - Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents - logs:DeleteLogGroup - logs:DescribeLogGroups Resource: - !Sub arn:aws:logs:ap-northeast-1:${AWS::AccountId}:log-group:/aws/codebuild/${ServiceName}-${Env}:* - !Sub arn:aws:logs:ap-northeast-1:${AWS::AccountId}:log-group:/aws/lambda/* - !Sub arn:aws:logs:ap-northeast-1:${AWS::AccountId}:log-group::log-stream:* Effect: Allow - Action: - codebuild:CreateReportGroup - codebuild:CreateReport - codebuild:UpdateReport - codebuild:BatchPutTestCases Resource: - !Sub arn:aws:codebuild:ap-northeast-1:${AWS::AccountId}:project/${ServiceName}-${Env} Effect: Allow - Action: - s3:CreateBucket - s3:DeleteBucket - s3:PutBucket - s3:GetObject - s3:GetObjectVersion - s3:GetBucketAcl - s3:GetBucketLocation - s3:PutObject - s3:ListBucket - s3:SetBucketEncryption - s3:GetEncryptionConfiguration - s3:PutEncryptionConfiguration - s3:PutBucketPolicy Resource: - '*' Effect: Allow - Action: - cloudformation:DescribeStackEvents - cloudformation:DescribeStackResources - cloudformation:DescribeStackResource - cloudformation:DescribeStacks - cloudformation:ValidateTemplate - cloudformation:CreateStack - cloudformation:UpdateStack - cloudformation:DeleteStack - cloudformation:ListStackResources Resource: - '*' Effect: Allow - Action: - iam:CreateRole - iam:DeleteRole - iam:DeleteRolePolicy - iam:PutRolePolicy - iam:GetRole - iam:PassRole Resource: - '*' Effect: Allow - Action: - lambda:UpdateFunctionCode - lambda:GetFunction - lambda:GetFunctionConfiguration - lambda:CreateFunction - lambda:DeleteFunction - lambda:ListVersionsByFunction - lambda:PublishVersion Resource: - !Sub arn:aws:lambda:ap-northeast-1:${AWS::AccountId}:function:${ServiceName}-${Env}* Effect: Allow AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Sid: '' Effect: Allow Principal: Service: codebuild.amazonaws.com Action: sts:AssumeRole # CodePipeline CodePipelineProject: Type: AWS::CodePipeline::Pipeline Properties: Name: !Sub ${ServiceName}-${Env} RoleArn: !GetAtt CodePipelineServiceRole.Arn Stages: - Name: Source Actions: - Name: SourceAction ActionTypeId: Category: Source Owner: AWS Version: 1 Provider: CodeCommit OutputArtifacts: - Name: SourceArtifact # デプロイもとのCodeCommitのリポジトリとブランチ Configuration: RepositoryName: serverless-example-repository BranchName: master # push時に自動でデプロイされないようにする PollForSourceChanges: false RunOrder: 1 - Name: Build Actions: - Name: BuildAction InputArtifacts: - Name: SourceArtifact OutputArtifacts: - Name: BuildArtifact ActionTypeId: Category: Build Owner: AWS Version: 1 Provider: CodeBuild Configuration: ProjectName: !Ref CodeBuildProject RunOrder: 2 ArtifactStore: Type: S3 Location: !Ref ArtifactsBucket # CodePipelineのIAMロール CodePipelineServiceRole: Type: AWS::IAM::Role Properties: RoleName: !Sub ${ServiceName}-CodePipelineServiceRole-${Env} Policies: - PolicyName: !Sub ${ServiceName}-CodePipelineServiceRolePolicy-${Env} PolicyDocument: Version: '2012-10-17' Statement: - Action: - s3:GetObject - s3:GetObjectVersion - s3:GetBucketVersioning - s3:PutObject Resource: - arn:aws:s3:::codepipeline* Effect: Allow - Action: - codecommit:CancelUploadArchive - codecommit:GetBranch - codecommit:GetCommit - codecommit:GetUploadArchiveStatus - codecommit:UploadArchive Resource: - '*' Effect: Allow - Action: - codebuild:BatchGetBuilds - codebuild:StartBuild Resource: - '*' Effect: Allow - Action: - codedeploy:CreateDeployment - codedeploy:GetApplication - codedeploy:GetApplicationRevision - codedeploy:GetDeployment - codedeploy:GetDeploymentConfig - codedeploy:RegisterApplicationRevision Resource: - '*' Effect: Allow - Action: - codestar-connections:UseConnection Resource: - '*' Effect: Allow - Action: - s3:* Resource: - '*' Effect: Allow AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - codepipeline.amazonaws.com Action: - sts:AssumeRole
スタックを作成する
先程のEnvを指定してそれぞれdev
とprd
のスタックを作成します。
デプロイする
スタック作成後に作成されたCodePipelineからデプロイできるかどうか確認します。
dev
とprd
でそれぞれのパイプラインが作成されているので選択して「変更をリリースする」を選択します。
デプロイが成功すればserverless frameworkが作成したスタックを確認することができます。
Lambda関数もdev
とprd
でそれぞれ別に出来上がっています。
おわりに
今回のCloudFormationテンプレートだとデプロイが全てmaster
ブランチからとなっていますが、環境ごとにデプロイもととなるブランチを変えたいといった場合などにはデプロイもとのブランチ名もEnv
などを含めたものにあわせて変更するなど、もうひと工夫必要になります。